
import { WsClient } from "tsrpc";
import { logger } from "../../tsgf/logger";
import { ServiceType as ClusterServiceType, serviceProto as clusterServiceProto } from "./protocols/serviceProto";

/**
 * 集群节点客户端
 * @date 2022/4/19 - 16:50:02
 *
 * @export
 * @class ClusterNodeClient
 * @typedef {ClusterNodeClient}
 * @template NodeInfo 节点信息的类型，可自定义
 */
export class ClusterNodeClient<NodeInfo = any>{

    private nodeId: string;
    private clusterKey: string;
    private getNodeInfo: () => NodeInfo;

    private clusterServerUrl: string;
    private clusterCAutoReconnectHD: any;
    clusterClient: WsClient<ClusterServiceType> | null = null;

    constructor(clusterServerUrl: string, nodeId: string, clusterKey: string, getNodeInfo: () => NodeInfo) {
        this.clusterServerUrl = clusterServerUrl;
        this.nodeId = nodeId;
        this.clusterKey = clusterKey;
        this.getNodeInfo = getNodeInfo;
    }


    /**
     * 获取集群服务的客户端，客户端连上之后会自动同步信息给管理服务器
     * @returns 
     */
    private getClusterClient(): WsClient<ClusterServiceType> {
        var client = new WsClient(clusterServiceProto, {
            server: this.clusterServerUrl,
            json: false,
            logger: logger,
        });
        var autoSyncInfoHD: any = 0;
        client.flows.postConnectFlow.push(v => {
            autoSyncInfoHD = setInterval(() => {
                if (!client.isConnected) {
                    clearInterval(autoSyncInfoHD);
                    return;
                }
                client.sendMsg("ClusterSyncNodeInfo", {
                    nodeInfo: this.getNodeInfo(),
                });
            }, 1000);
            return v;
        });
        client.flows.postDisconnectFlow.push(v => {
            clearInterval(autoSyncInfoHD);
            return v;
        });

        return client;
    }


    /**
     * 连接集群服务器,失败返回错误消息，连上了之后如果非手动断开，则会自动重连
     * @returns cluster join 
     */
    public async joinCluster(): Promise<string | null> {
        if (this.clusterClient && this.clusterClient.isConnected) {
            this.clusterClient.disconnect();
        }
        this.clusterClient = this.getClusterClient();
        var connectRet = await this.clusterClient.connect();
        if (!connectRet.isSucc) {
            return "连接失败:" + connectRet.errMsg;
        }
        let ret = await this.clusterClient.callApi("ClusterLogin", {
            nodeId: this.nodeId,
            clusterKey: this.clusterKey,
            nodeInfo: this.getNodeInfo(),
        });
        if (!ret.isSucc) {
            return ret.err.message;
        }
        //成功连上后,设置集群断开自动重连
        this.clusterClient.flows.postDisconnectFlow.push(async v => {
            if (!v.isManual) {
                logger.error('集群服务器-连接断开,等待2秒后自动重连');
                clearTimeout(this.clusterCAutoReconnectHD);
                this.clusterCAutoReconnectHD = setTimeout(() => this.reJoinCluster(true), 2000);
            }
            return v;
        });
        return null;
    }
    /**
     * 当集群断开后用于重新连接集群
     * @param [failReTry] 
     * @returns join  cluster 
     */
    private async reJoinCluster(failReTry: boolean = true): Promise<boolean> {
        const err = await this.joinCluster();
        // 重连也错误，弹出错误提示
        if (!err) {
            logger.log('集群服务器-重连成功!');
            return true;
        }
        if (failReTry) {
            logger.error('集群服务器-重连失败:' + err + '  2秒后自动重连!');
            clearTimeout(this.clusterCAutoReconnectHD);
            this.clusterCAutoReconnectHD = setTimeout(() => this.reJoinCluster(failReTry), 2000);
        } else {
            logger.error('集群服务器-重连失败:' + err);
        }
        return false;
    }
}